function HSB2RGB(hue, sat, val)
{
	var red, green, blue,
	i, f, p, q, t;

	if (val == 0)
		return [ 0, 0, 0 ];
	
	hue *= 0.016666667; // /= 60;
	sat *= 0.01; // /= 100;
	val *= 0.01; // /= 100;
		
	i = Math.floor(hue);
	f = hue - i;
	p = val * (1 - sat);
	q = val * (1 - (sat * f));
	t = val * (1 - (sat * (1 - f)));
	
	switch(i)
	{
		case 0: red = val; green = t; blue = p; break;
		case 1: red = q; green = val; blue = p; break;
		case 2: red = p; green = val; blue = t; break;
		case 3: red = p; green = q; blue = val; break;
		case 4: red = t; green = p; blue = val; break;
		case 5: red = val; green = p; blue = q; break;
	}
	
	return [red, green, blue];
}

function RGB2HSB(red, green, blue)
{
	var x, f, i, hue, sat, val;

	x = Math.min( Math.min( red, green ), blue );
	val = Math.max( Math.max( red, green ), blue );

	if (x==val)
		return [0, 0, val*100];

	f = (red == x) ? green - blue : ((green == x) ? blue - red : red - green);
	i = (red == x) ? 3 : ((green == x) ? 5 : 1);
	
	hue = Math.floor((i - f / (val - x)) * 60) % 360;
	sat = Math.floor(((val - x) / val) * 100);
	val = Math.floor(val * 100);
	
	return [hue, sat, val];
}

function flood(startX, startY) {
    var colorLayerData = context.getImageData(100,100,WINDOW_WIDTH,WINDOW_HEIGHT);
    var pixelPos = (startY * DRAWABLE_WIDTH + startX) * 4;

    //console.log("outline: " + outlineLayerData.data[pixelPos] +","+ outlineLayerData.data[pixelPos+1] +","+ outlineLayerData.data[pixelPos+2] +","+ outlineLayerData.data[pixelPos+3]);

    var r = colorLayerData.data[pixelPos + 0];
    var g = colorLayerData.data[pixelPos + 1];
    var b = colorLayerData.data[pixelPos + 2];
    var a = colorLayerData.data[pixelPos + 3];
    //console.log("clicked color:   " + r +","+ g +","+ b +","+ a);

    clickedColorR = r;
    clickedColorG = g;
    clickedColorB = b;

    newColorR = color[curColorIndex].r;
    newColorG = color[curColorIndex].g;
    newColorB = color[curColorIndex].b;

    //console.log("new color:   " + newColorR +","+ newColorG +","+ newColorB);

    if (clickedColorR == newColorR && clickedColorG == newColorG && clickedColorB == newColorB) {
        //console.log("Return because trying to fill with the same color");
        return;
    }

    if (outlineLayerData.data[pixelPos] + outlineLayerData.data[pixelPos + 1] + outlineLayerData.data[pixelPos + 2] == 0 && outlineLayerData.data[pixelPos + 3] == 255) {
        //console.log("Return because clicked outline: " + outlineLayerData.data[pixelPos+4]);
        return;
    }

    //console.log("PUSH: " + (startX - drawingAreaX - 2) + "," + (startY - drawingAreaY - 2));
    pixelStack = [[startX, startY]];

    floodFill();
}

function floodFill() {
    var newPos, x, y, pixelPos, reachLeft, reachRight;
    var drawingBoundLeft = drawingAreaX;
    var drawingBoundTop = drawingAreaY;
    var drawingBoundRight = drawingAreaX + drawingAreaWidth - 1;
    var drawingBoundBottom = drawingAreaY + drawingAreaHeight - 1;

    while (pixelStack.length) {
        newPos = pixelStack.pop();
        x = newPos[0];
        y = newPos[1];

        //console.log("POP: " + (x - drawingAreaX - 2) + "," + (y - drawingAreaY - 2));

        pixelPos = (y * canvasWidth + x) * 4;
        // Go up as long as the color matches and are inside the canvas
        while (y-- >= drawingBoundTop && matchClickedColor(pixelPos)) {
            //console.log("UP: " + (x - drawingAreaX - 2) + "," + (y - drawingAreaY - 2));
            pixelPos -= canvasWidth * 4;
        }
        pixelPos += canvasWidth * 4;
        ++y;
        reachLeft = false;
        reachRight = false;
        // Go down as long as the color matches and in inside the canvas
        while (y++ < drawingBoundBottom && matchClickedColor(pixelPos)) {
            colorPixel(pixelPos);
            //console.log("COLOR: " + (x - drawingAreaX - 2) + "," + (y - drawingAreaY - 2));

            if (x > drawingBoundLeft) {
                if (matchClickedColor(pixelPos - 4)) {
                    if (!reachLeft) {
                        pixelStack.push([x - 1, y]);
                        //console.log("PUSH: " + ((x-1) - drawingAreaX - 2) + "," + (y - drawingAreaY - 2));
                        reachLeft = true;
                    }
                } else if (reachLeft) {
                    reachLeft = false;
                }
            }
            if (x < drawingBoundRight) {
                if (matchClickedColor(pixelPos + 4)) {
                    if (!reachRight) {
                        pixelStack.push([x + 1, y]);
                        //console.log("PUSH: " + ((x+1) - drawingAreaX - 2) + "," + (y - drawingAreaY - 2));
                        reachRight = true;
                    }
                } else if (reachRight) {
                    reachRight = false;
                }
            }

            pixelPos += canvasWidth * 4;
        }
    }
    redraw();
}

function matchClickedColor(pixelPos) {
    var r = outlineLayerData.data[pixelPos];
    var g = outlineLayerData.data[pixelPos + 1];
    var b = outlineLayerData.data[pixelPos + 2];
    var a = outlineLayerData.data[pixelPos + 3];

    // If current pixel is black then it is an outline
    if (r + g + b == 0 && a == 255) { return false; }

    r = colorLayerData.data[pixelPos];
    g = colorLayerData.data[pixelPos + 1];
    b = colorLayerData.data[pixelPos + 2];

    // If the current pixel matches the clicked color
    if (r == clickedColorR && g == clickedColorG && b == clickedColorB) return true;

    // If current pixel matches the new color
    if (r == newColorR && g == newColorG && b == newColorB) return false;

    return true;
}

function colorPixel(pixelPos) {
    colorLayerData.data[pixelPos] = newColorR;
    colorLayerData.data[pixelPos + 1] = newColorG;
    colorLayerData.data[pixelPos + 2] = newColorB;
    colorLayerData.data[pixelPos + 3] = 255;
}